#include "../stream/inputbufferstream.h"
#include "../stream/outputbufferstream.h"
#include "../sort/dWayMerge_class.h"
#include "../stream/inputbufferstream.h"
#include "../sort/quicksort.h"
#include "../sort/random.h"
#include <sys/time.h>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <cstdio>
#include <queue>


using namespace std;

int main(int argc, char *argv[])
{
	if(argc!=5)
	{
		std::cout << "usage is : " << argv[0] << " [fileName] [N] [M] [d]" << std::endl;
		exit(0);
	}
	char *fileName = argv[1];
	int N = atoi(argv[2]);
	int M = atoi(argv[3]);
	int d = atoi(argv[4]);
	dWayMerge dwm;
	struct timeval start, end;
        long utime, seconds, useconds;

	Element e;
	if(!(N&&M&&d))
	{
		cout << " Please recheck the input ";
		return -1;
	}

	if(!dwm.heapIntialize(d))
	{
		std::cout << "failed to allocate memory";
	}
	random(fileName, N);
	split_data(fileName, N, N/M);
	
	inputbufferstream is[(N/M)*5];
	queue <int> queueForStream;
	int dbufstream[d];
	
	for(int i=0;i<N/M;i++)
        {
                queueForStream.push(i);
        }
        
        int queueSize = queueForStream.size();
        outputbufferstream dway;
	int index = (N/M) + 1;
	int counter;
	int loop;
	//start timer
	gettimeofday(&start, NULL);
       
        while( queueSize >1 )
        {
		if(queueSize>=d)
		counter = d ;
		else 
		counter = queueSize;
		
		loop = counter;
	
		for(int i = 0;i< loop;i ++ )
		{
               		dbufstream[i] = queueForStream.front();
			queueForStream.pop();
         		stringstream ss;
             		ss << dbufstream[i];		
			is[dbufstream[i]].open_s(ss.str().c_str());
               		int a = is[dbufstream[i]].read_next();
			if(a != EOF) 
			{
       	                        e.data = a;
               	                e.index = dbufstream[i];
                       	        dwm.heapInsert(e);
			}
                       	else
                        {
                               	counter--;
                        }	

		}
		stringstream ss;
		ss << index;		
		dway.create(ss.str().c_str());
		while(counter)
		{
			int a;
			if(!dwm.heapIsEmpty())
			{
				e = dwm.heapRemoveMax();      		
				dway.write_s(e.data);
			}
			a = is[e.index].read_next();
			if(a!=EOF)
                        {
                                e.data = a;
                                dwm.heapInsert(e);
                        }
                        else
                                counter--;

		}

		dway.close_s();
		queueForStream.push(index);
		queueSize = queueForStream.size();
		index++;
			
	}

	index = queueForStream.front();
	stringstream ss;
        ss << index;
        inputbufferstream final;
	final.open_s(ss.str().c_str());
	
	//end of time
	gettimeofday(&end, NULL);

        seconds = end.tv_sec - start.tv_sec;
        useconds = end.tv_usec - start.tv_usec;
        utime = ((seconds) * 1000 *1000 + useconds);

        cout<< "For N M d : " << N <<" " << M << " " << d << " " << utime << endl;

	/*
	counter = N;
	
        while(counter)
        {
        	cout << final.read_next() << endl;
        	counter--;
        }
	*/
	
}
